﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Text.RegularExpressions;

using Stock.Model;
using Stock.Util;
using Stock.Model.Input;
using Newtonsoft.Json.Linq;
using HtmlAgilityPack;

namespace Stock.Service
{
    public class EasyMoneyService : BaseService
    {
        private readonly string index_stock_file_name = "index_stock.json";
        private readonly string stock_file_name = "stock.json";
        public EasyMoneyService() : base(AppConst.EASY_MONEY_URL)
        {

        }

        public async Task Update(StockType type, List<StockModel> list)
        {
            await Task.Factory.StartNew(() =>
           {
               string path = GetFilePath(type == StockType.IndexStock ? index_stock_file_name : stock_file_name);
               FileUtil.WriteAllText(path, StringUtil.ToJson(list));
           });
        }

        public async Task UpdateMarketType(StockType type, List<StockModel> list)
        {
            foreach (var item in list)
            {
                var stockList = GetStockList(item.Code);
                var model = stockList.FirstOrDefault(m => m.Code == item.Code && m.Name == item.Name && m.MktNum == item.MktNum);
                if (model != null)
                {
                    item.MarketType = model.MarketType;
                }
            }

            await Update(type, list);
        }

        public void UpdateMarketType(StockModel item)
        {
            var stockList = GetStockList(item.Code);
            var model = stockList.FirstOrDefault(m => m.Code == item.Code && m.Name == item.Name && m.MktNum == item.MktNum);
            if (model != null)
            {
                item.MarketType = model.MarketType;
            }
        }

        #region 操作股票
        public async Task<List<StockModel>> GetStockList(StockType type)
        {
            return await Task.Factory.StartNew(() =>
            {
                string path = GetFilePath(type == StockType.IndexStock ? index_stock_file_name : stock_file_name);
                string json = FileUtil.ReadAllText(path);
                if (string.IsNullOrEmpty(json))
                {
                    return new List<StockModel>();
                }

                var list = StringUtil.Parse<List<StockModel>>(json);
                int maxNo = 0;
                if (StringUtil.IsNotEmpty(list))
                {
                    maxNo = list.Max(m => m.No);
                }
                if (maxNo < 1)
                {
                    maxNo = AppConst.VALUE_STOCK_LIST_MAX_COUNT;
                }

                list = list.OrderByDescending(m => m.No).ThenByDescending(m => m.Number).ToList();
                for (int i = 0; i < list.Count; i++)
                {
                    StockModel item = list[i];
                    if (i == 0)
                    {
                        if (item.No < 1)
                        {
                            item.No = maxNo;
                            continue;
                        }
                    }

                    if (item.No < 1)
                    {
                        item.No = list[i - 1].No - 1;
                    }
                }
                return list;
            });
        }

        public List<StockModel> GetStockList(string word)
        {
            if (string.IsNullOrEmpty(word))
            {
                return new List<StockModel>();
            }

            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("input", word);
            dic.Add("_", StringUtil.GetTimeStamp());
            var result = Get<JObject>(AppConst.EASY_MONEY_SEARCH_URL, dic, false);

            List<StockModel> list = new List<StockModel>();
            if (result != null && result.Flag)
            {
                if (result.Data != null)
                {
                    var table = result.Data.Value<JObject>("QuotationCodeTable");
                    if (table != null)
                    {
                        var array = table.Value<JArray>("Data");
                        if (array != null && array.Count > 0)
                        {
                            foreach (JToken item in array)
                            {
                                StockModel model = new StockModel
                                {
                                    Code = item.Value<string>("Code"),
                                    Name = item.Value<string>("Name"),
                                    MktNum = item.Value<string>("MktNum"),
                                    MarketType = item.Value<string>("MarketType")
                                };
                                string classify = item.Value<string>("Classify");
                                if (string.IsNullOrEmpty(classify))
                                {
                                    classify = "";
                                }
                                classify = classify.ToLower();
                                model.Type = classify.IndexOf("fund") > -1 ? "0" : "1";
                                list.Add(model);
                            }
                        }
                    }
                }
            }
            return list;
        }

        public async Task<StockModel> GetStockModel(GetStockInput input)
        {
            StockModel model = new StockModel()
            {
                MktNum = input.MktNum,
                Code = input.Code,
                Type = input.Type
            };

            return await GetStockModel(model, input.Flag);
        }

        public async Task<StockModel> GetStockModel(StockModel model, bool flag)
        {
            if (model.IsOTCFund())
            {
                return await GetStockModel(model);
            }

            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("secid", $"{model.MktNum}.{model.Code}");
            dic.Add("fields", "f43,f169,f170,f46,f60,f84,f116,f44,f45,f171,f126,f47,f48,f168,f164,f49,f161,f55,f92,f59,f152,f167,f50,f86,f71,f172,f191,f192,f51,f52,f58");
            if (model.Type == "1")
            {
                dic.Add("invt", "2");
                dic.Add("fltt", "2");
            }
            dic.Add("_", StringUtil.GetTimeStamp());
            var result = await GetAsync<JObject>("/api/qt/stock/get", dic);

            if (result != null && result.Flag)
            {
                if (result.Data != null)
                {
                    int n = flag ? 100 : 1000;
                    var data = result.Data.Value<JObject>("data");
                    if (data == null)
                    {
                        return model;
                    }
                    model.Name = data.Value<string>("f58");
                    if (model.Type == "0")
                    {
                        model.Price = data.Value<double>("f43") / n;
                        model.Change = data.Value<double>("f169") / n;
                        model.ChangePercent = (data.Value<double>("f170") / 100) + "%";
                    }
                    else
                    {
                        model.Price = data.Value<double>("f43");
                        model.Change = data.Value<double>("f169");
                        model.ChangePercent = data.Value<string>("f170") + "%";
                    }
                }
            }
            return model;
        }

        public async Task<StockModel> GetStockModel(StockModel model)
        {
            string url = string.Format(AppConst.EASY_MONEY_FUND_UPDATE_URL, model.Code, StringUtil.GetTimeStamp());
            var result = await GetStringAsync(url, useBaseUrl: false);
            if (result != null && result.Flag)
            {
                string data = result.Data;
                if (!string.IsNullOrEmpty(data))
                {
                    Regex reg = new Regex(@"^jsonpgz\((.*)\)", RegexOptions.IgnoreCase);
                    Match match = reg.Match(data);
                    if (match.Success)
                    {
                        string json = match.Groups[1].Value;
                        var obj = StringUtil.Parse<JObject>(json);
                        if (obj != null)
                        {
                            model.Name = obj.Value<string>("name");
                            model.Price = obj.Value<double>("gsz");
                            model.ChangePercent = obj.Value<string>("gszzl") + "%";
                            model.Change = StringUtil.ToFixed(model.Price - obj.Value<double>("dwjz"), 3);
                        }
                    }
                }
            }
            return model;
        }
        #endregion

        #region 操作基金

        public async Task<FundModel> GetFundModel(string code)
        {
            string url = string.Format(AppConst.EASY_MONEY_FUND_INFO_URL, code);
            var result = await GetStringAsync(url, null, false);
            string html = result.Flag ? result.Data : "";
            return ParseFundModel(html);
        }

        public async Task<List<FundMemberModel>> GetFundMemberList(string code)
        {
            string url = string.Format(AppConst.EASY_MONEY_FUND_MEMBER_URL, code, StringUtil.GetTimeStamp());
            var result = await GetStringAsync(url, null, false);
            string html = result.Flag ? result.Data : "";
            return ParsetFundMemberList(html);
        }

        public async Task<FundHistoryJZModel> GetFundJZModel(int pageIndex, int pageSize, string code)
        {
            string url = string.Format(AppConst.EASY_MONEY_FUND_JZ_URL, code, pageIndex, pageSize, StringUtil.GetTimeStamp());
            var result = await GetAsync<JObject>(url, null, false, httpItem =>
            {
                httpItem.Host = AppConst.EASY_MONEY_FUND_API_HOST;
                httpItem.Referer = AppConst.EASY_MONEY_FUND__API_URL;
            });
            FundHistoryJZModel model = new FundHistoryJZModel();

            if (result != null && result.Flag)
            {
                if (result.Data != null)
                {
                    model.TotalCount = result.Data.Value<int>("TotalCount");
                    var data = result.Data.Value<JObject>("Data");
                    if (data != null)
                    {
                        var dataList = data.Value<JArray>("LSJZList");
                        if (dataList != null && dataList.Count > 0)
                        {
                            foreach (var item in dataList)
                            {
                                string jjzzl = item.Value<string>("JZZZL");
                                FundJZModel jzModel = new FundJZModel()
                                {
                                    FSRQ = item.Value<string>("FSRQ"),
                                    DWJZ = item.Value<string>("DWJZ"),
                                    JJZZL = StringUtil.ToDouble(jjzzl),
                                    JJZZLP = $"{jjzzl}%",
                                    LJJZ = item.Value<string>("LJJZ")
                                };
                                model.List.Add(jzModel);
                            }
                        }
                    }
                }
            }
            return model;
        }

        private FundModel ParseFundModel(string html)
        {
            FundModel model = new FundModel();
            try
            {
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(html);

                var root = doc.DocumentNode;
                var trs = GetNodeList(root, "//div[@class='txt_in']/div[@class='box']/table/tr");

                if (trs != null && trs.Count > 9)
                {
                    model.FullName = GetNodeText(trs[0], "td[1]");
                    model.ShortName = GetNodeText(trs[0], "td[2]");
                    model.Code = GetNodeText(trs[1], "td[1]");
                    model.Type = GetNodeText(trs[1], "td[2]");
                    model.IssueDate = GetNodeText(trs[2], "td[1]");
                    model.BuildDate = GetNodeText(trs[2], "td[2]");
                    model.AssetsScale = GetNodeText(trs[3], "td[1]");
                    model.ShareScale = GetNodeText(trs[3], "td[2]");
                    model.Company = GetNodeText(trs[4], "td[1]");
                    model.Trusteeship = GetNodeText(trs[4], "td[2]");
                    model.Manager = GetNodeText(trs[5], "td[1]");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            return model;
        }

        private List<FundMemberModel> ParsetFundMemberList(string html)
        {
            List<FundMemberModel> list = new List<FundMemberModel>();
            try
            {
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(html);

                var root = doc.DocumentNode;
                var trs = GetNodeList(root, "/div[1]//table/tbody/tr");
                if (trs != null && trs.Count > 0)
                {
                    foreach (HtmlNode item in trs)
                    {
                        FundMemberModel model = new FundMemberModel
                        {
                            Code = GetNodeText(item, "td[2]"),
                            Name = GetNodeText(item, "td[3]"),
                            Percent = GetNodeText(item, "td[7]"),
                            Number = StringUtil.ToFixed(GetNodeText(item, "td[8]")),
                            TotalPrice = StringUtil.ToFixed(GetNodeText(item, "td[9]"))
                        };
                        list.Add(model);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            return list;
        }
        #endregion
    }
}
